
#include "ParaTreeModel.h"

#include <algorithm/shared/data/scene/Air.h>
#include <algorithm/shared/data/scene/Camera.h>
#include <algorithm/shared/data/scene/Cloud.h>
#include <algorithm/shared/data/scene/Heliostat.h>
#include <algorithm/shared/data/scene/Location.h>
#include <algorithm/shared/data/scene/Node.h>
#include <algorithm/shared/data/scene/Ordinary.h>
#include <algorithm/shared/data/scene/Receiver.h>
#include <algorithm/shared/data/scene/Sun.h>
#include <algorithm/shared/data/scene/Terrain.h>
#include <algorithm/shared/data/topology/geometry/BSpline.h>
#include <algorithm/shared/data/topology/geometry/Cylinder.h>
#include <algorithm/shared/data/topology/geometry/Geometry.h>
#include <algorithm/shared/data/topology/geometry/Mesh.h>
#include <algorithm/shared/data/topology/geometry/MultiPanel.h>
#include <algorithm/shared/data/topology/geometry/Parabolic.h>
#include <algorithm/shared/data/topology/geometry/Rectangle.h>
#include <algorithm/shared/data/topology/geometry/RefinedCylinder.h>
#include <algorithm/shared/data/topology/geometry/RefinedRectangle.h>
#include <algorithm/shared/data/topology/material/Absorb.h>
#include <algorithm/shared/data/topology/material/Material.h>
#include <algorithm/shared/data/topology/material/Reflect.h>
#include <algorithm/shared/data/topology/material/Refract.h>
#include <algorithm/shared/data/world/air/Attenuation.h>
#include <algorithm/shared/data/world/air/CustomAttenuation.h>
#include <algorithm/shared/data/world/air/ExponentialAttenuation.h>
#include <algorithm/shared/data/world/air/VacuumAttenuation.h>
#include <algorithm/shared/data/world/sun/sun_position/SunPosition.h>
#include <algorithm/shared/data/world/sun/sunshape/BuieSunShape.h>
#include <algorithm/shared/data/world/sun/sunshape/GaussianSunShape.h>
#include <algorithm/shared/data/world/sun/sunshape/PillboxSunShape.h>
#include <algorithm/shared/data/world/sun/sunshape/SunShape.h>
#include <algorithm/shared/utils/Grid.h>
#include <algorithm/shared/utils/Para.h>
#include <algorithm/shared/utils/Vec2.h>
#include <ui/tree/ParaTreeNode.h>
#include <utils/ParaUtils.h>
#include <utils/StringUtils.h>

// #include "SetAndGetPara.h"
#include <QMap>

#include <iostream>
#include <utility>

namespace pt = boost::property_tree;

namespace solar
{

    ParaTreeModel::ParaTreeModel(TreeModelType _model_type, QSharedPointer<Para> _para,
                                 QObject* parent)
        : QAbstractItemModel(parent), model_type(_model_type), para(std::move(_para))
    {

        this->role_names_ = QHash<int, QByteArray>(QAbstractItemModel::roleNames());
        this->role_names_[NAME] = "name";
        this->role_names_[PARA] = "para";

        root_node = createNode(nullptr, "root",
                               ""); // 建立根节点,这个节点在视图中不显示,因此其他参数部分采用默认值

        // qDebug() <<"++++1";
        switch (model_type)
        {

        case LOCATION:
        {
            buildLocationTreeModel(para.dynamicCast<Location>());
            setLabelTxt("location");
            break;
        }
        case SUN:
        {
            buildSunTreeModel(para.dynamicCast<Sun>());
            setLabelTxt("sun");
            break;
        }
        case AIR:
        {
            buildAirTreeModel(para.dynamicCast<Air>());
            setLabelTxt("air");
            break;
        }
        case TERRAIN:
        {
            buildTerrainTreeModel(para.dynamicCast<Terrain>());
            setLabelTxt("terrain");
            break;
        }
        case CAMERA:
        {
            buildCameraTreeModel(para.dynamicCast<Camera>());
            setLabelTxt("camera");
            break;
        }
        case CLOUD:
        {
            buildCloudTreeModel(para.dynamicCast<Cloud>());
            setLabelTxt("cloud");
            break;
        }
        case NODE:
        {
            buildNodeTreeModel(para.dynamicCast<Node>());
            setLabelTxt("node");
            break;
        }
        case HELIOSTAT:
        {
            // qDebug() <<"++++2";
            buildHeliostatTreeModel(para.dynamicCast<Heliostat>());
            // qDebug() <<"++++3";
            setLabelTxt("heliostat");
            break;
        }
        case RECEIVER:
        {
            buildReceiverTreeModel(para.dynamicCast<Receiver>());
            setLabelTxt("receiver");
            break;
        }
        case ORDINARY:
        {
            buildOrdinaryTreeModel(para.dynamicCast<Ordinary>());
            setLabelTxt("ordinary");
            break;
        }
        }
    }
    ParaTreeModel::~ParaTreeModel() {}

    /**
     * 两项任务：一是改变para指针中的内容，二是改变界面中的内容
     */
    void ParaTreeModel::setParaViaPTree(pt::ptree tree)
    {
        // beginResetModel();
        switch (model_type)
        {
        case LOCATION:
        {
            // ！！！！注意各个节点在build时的顺序
            updateParaViaPTree(root_node.get(), 0, tree, "site_name");
            updateParaViaPTree(root_node.get(), 1, tree, "longitude");
            updateParaViaPTree(root_node.get(), 2, tree, "latitude");
            // qDebug() << "==============finish LOCATION";
            break;
        }
        case SUN:
        {
            auto sunposition_node = root_node->child(0).get();
            pt::ptree sunposition_tree = tree.get_child("sun_position");
            updateParaViaPTree(sunposition_node, 0, sunposition_tree, "azimuth");
            updateParaViaPTree(sunposition_node, 1, sunposition_tree, "elevation");
            updateParaViaPTree(sunposition_node, 2, sunposition_tree, "dni");
            updateParaViaPTree(sunposition_node, 3, sunposition_tree, "trackable");

            updateParaViaPTree(root_node.get(), 1, tree, "sun_shape.type");

            auto sunshape_node = root_node->child(1).get();
            pt::ptree sunshape_tree = tree.get_child("sun_shape");
            std::string sunshape_type = sunshape_tree.get<std::string>("type");
            if (sunshape_type == "Buie")
            {
                updateParaViaPTree(sunshape_node, 0, sunshape_tree, "csr");
                // qDebug() <<"1";
            }
            if (sunshape_type == "Gaussian")
            {
                updateParaViaPTree(sunshape_node, 0, sunshape_tree, "sigma");
            }
            if (sunshape_type == "Pillbox")
            {
                updateParaViaPTree(sunshape_node, 0, sunshape_tree, "theta_max");
            }
            // qDebug() <<"2";
            // qDebug() << "==============finish SUN";
            break;
        }
        case AIR:
        {
            // qDebug() <<"5";
            updateParaViaPTree(root_node.get(), 0, tree, "attenuation.type");
            // qDebug() <<"6";
            auto attenuation_node = root_node->child(0).get();
            pt::ptree attenuation_tree = tree.get_child("attenuation");
            std::string attenuation_type = attenuation_tree.get<std::string>("type");
            if (attenuation_type == "Exponential")
            {
                updateParaViaPTree(attenuation_node, 0, attenuation_tree, "beta");
            }
            // qDebug() << "==============finish AIR";
            break;
        }
        case TERRAIN:
        {
            updateParaViaPTree(root_node.get(), 0, tree, "dem_file");
            // qDebug() << "==============finish TERRAIN";
            break;
        }
        case CAMERA:
        {
            break;
        }
        case CLOUD:
        {
            updateParaViaPTree(root_node.get(), 0, tree, "cloud_file");
            // qDebug() << "==============finish CLOUD";
            break;
        }
        /**
         * 以下TOPO的类型，与前面六种类型的处理方式不同
         */
        case NODE: // node类型，传入的ptree是从“position”标签开始的
        {
            // node---只设置translation
            float x = tree.get<float>("x");
            float y = tree.get<float>("y");
            float z = tree.get<float>("z");
            auto translation_node = root_node->child(0).get();
            std::string value = Vec3(x, y, z).toString();
            translation_node->setData(QString::fromStdString(value), 1);
            updateNodePara(translation_node, value);

            // qDebug() << "==============finish NODE";
            break;
        }
        case HELIOSTAT:
        {
            updateParaViaPTree(root_node.get(), 1, tree, "subhelio_row_col", 2);
            updateParaViaPTree(root_node.get(), 2, tree, "gap", 2);

            auto geometry_node = root_node->child(3).get(); // 假设helio均为rectangle，因此不予处理
            pt::ptree geometry_tree = tree.get_child("geometry");
            updateParaViaPTree(geometry_node, 0, geometry_tree, "size", 2);

            updateParaViaPTree(root_node.get(), 4, tree, "material.type");

            auto material_node = root_node->child(4).get();
            pt::ptree material_tree = tree.get_child("material");
            std::string material_type = material_tree.get<std::string>("type");
            if (material_type == "Reflect")
            {
                updateParaViaPTree(material_node, 0, material_tree, "reflectivity");
                updateParaViaPTree(material_node, 1, material_tree, "slope_error_type");
                updateParaViaPTree(material_node, 2, material_tree, "slope");
            }
            if (material_type == "Refract")
            {
                updateParaViaPTree(material_node, 0, material_tree, "transmissivity");
                updateParaViaPTree(material_node, 1, material_tree, "air_refractive_index");
                updateParaViaPTree(material_node, 2, material_tree, "glass_refractive_index");
                updateParaViaPTree(material_node, 3, material_tree, "glass_thickness");
                updateParaViaPTree(material_node, 4, material_tree, "slope_error_type");
                updateParaViaPTree(material_node, 5, material_tree, "slope");
            }

            updateParaViaPTree(root_node.get(), 5, tree, "thickness");
            updateParaViaPTree(root_node.get(), 6, tree, "has_brace");

            // qDebug() << "==============finish HELIOSTAT";
            break;
        }
        case RECEIVER:
        {
            // qDebug() << "==============start RECEIVER";
            updateParaViaPTree(root_node.get(), 1, tree, "geometry.type");

            auto geometry_node = root_node->child(1).get(); // 假设helio均为rectangle，因此不予处理
            pt::ptree geometry_tree = tree.get_child("geometry");
            std::string geometry_type = geometry_tree.get<std::string>("type");
            if (geometry_type == "Rectangle")
            {
                updateParaViaPTree(geometry_node, 0, geometry_tree, "size", 2);
            }
            if (geometry_type == "Cylinder")
            {
                updateParaViaPTree(geometry_node, 0, geometry_tree, "height");
                updateParaViaPTree(geometry_node, 1, geometry_tree, "radius");
            }
            if (geometry_type == "RefinedRectangle")
            {
                updateParaViaPTree(geometry_node, 0, geometry_tree, "size", 2);
                updateParaViaPTree(geometry_node, 1, geometry_tree, "tube_radius");
            }
            if (geometry_type == "RefinedCylinder")
            {
                updateParaViaPTree(geometry_node, 0, geometry_tree, "height");
                updateParaViaPTree(geometry_node, 1, geometry_tree, "radius");
                updateParaViaPTree(geometry_node, 2, geometry_tree, "tube_radius");
                updateParaViaPTree(geometry_node, 3, geometry_tree, "tube");
                updateParaViaPTree(geometry_node, 4, geometry_tree, "tube_unit");
                updateParaViaPTree(geometry_node, 5, geometry_tree, "panel");
            }

            auto material_node = root_node->child(2).get();
            pt::ptree material_tree = tree.get_child("material");
            updateParaViaPTree(material_node, 0, material_tree, "absorptivity");

            // qDebug() << "==============finish RECEIVER";
            break;
        }
        case ORDINARY:
        {
            /**
             * TODO:: add ordinary in .json file
             */
            break;
        }
        }
        // endResetModel();
    }

    /**
     * 更新parent_node下第k个孩子节点，更新的值从tree中标签name获取，
     * xyz表示name标签是否进一步细分为几个标签---1-没有进一步细分，2-细分为x、y，3-细分为x、y、z
     */
    void ParaTreeModel::updateParaViaPTree(ParaTreeNode* parent_node, int k, pt::ptree tree,
                                           std::string name, int xyz)
    {
        std::string value;
        switch (xyz)
        {
        case 1:
            value = tree.get<std::string>(name);
            break;
        case 2:
        {
            float x = tree.get<float>(name + ".x");
            float y = tree.get<float>(name + ".y");
            value = Vec2(x, y).toString();
            break;
        }
        case 3:
        {
            float x = tree.get<float>(name + ".x");
            float y = tree.get<float>(name + ".y");
            float z = tree.get<float>(name + ".z");
            value = Vec3(x, y, z).toString();
            break;
        }
        }
        // std::cout <<" value = " << value << std::endl;

        auto child_node = parent_node->child(k).get();
        int child_node_state = child_node->getState();

        // std::cout <<"k = "<<k << ", child_node_state = " << child_node_state << std::endl;
        switch (child_node_state)
        {
        case OPTIONAL:
        {
            std::string current_value = child_node->data(1).toString().toStdString();
            // std::cout <<"current_value = "<< current_value << std::endl;

            if (value != current_value)
            {
                // std::cout <<"makechoice brefore\n";
                makeChoice(child_node, QString::fromStdString(value));
                // std::cout <<"makechoice after\n";
            }
            break;
        }
        case EDITABLE:
        {
            child_node->setData(QString::fromStdString(value), 1);
            break;
        }
        }

        switch (model_type)
        {
        case LOCATION:
            updateLocationPara(child_node, value);
            break;
        case SUN:
            updateSunPara(child_node, value);
            break;
        case AIR:
            updateAirPara(child_node, value);
            break;
        case TERRAIN:
            updateTerrainPara(child_node, value);
            break;
        case CAMERA:
            updateCameraPara(child_node, value);
            break;
        case CLOUD:
            updateCloudPara(child_node, value);
            break;
        case NODE:
            updateNodePara(child_node, value);
            break;
        case HELIOSTAT:
            updateHeliostatPara(child_node, value);
            break;
        case RECEIVER:
            updateReceiverPara(child_node, value);
            break;
        case ORDINARY:
            updateOrdinaryPara(child_node, value);
            break;
        }
    }

    /*
    ---------------------------------------------------------------------------
    建立模型相关的函数
    ！！！！！！！！！！！！！！！！！！！！！！！！
    问题：：：在这里设置参数的初始值然后传到para里 or 直接在Para的子类中初始化参数值这里只获取 ？
            目前是，在Para子类中初始化，这里获取参数值
*/

    // state是当前节点的state
    auto ParaTreeModel::createNode(const QSharedPointer<ParaTreeNode>& parent,
                                   const QVariant& data1, const QVariant& data2, ParaState state,
                                   bool is_current_option_child,
                                   const QString& parent_option) -> QSharedPointer<ParaTreeNode>
    {
        QList<QVariant> list;
        list.append(data1);
        list.append(data2);
        QSharedPointer<ParaTreeNode> child_node =
            QSharedPointer<ParaTreeNode>(new ParaTreeNode(list, parent));

        child_node->setState(state);

        if (parent == nullptr)
        {
            return child_node;
        }

        ParaState parent_state = parent->getState();
        if (parent_state == OPTIONAL)
        {
            parent->addOptionChild(parent_option, child_node);
            if (is_current_option_child)
            {
                parent->appendChild(child_node);
                if (parent->data(1).toString() !=
                    parent_option) // 都已经选中了这一option，父节点的data(1)存的应该就是option
                {
                    parent->setData(parent_option, 1); // 这里的if语句貌似不会执行
                }
            }
        }
        else
        {
            parent->appendChild(child_node);
        }

        return child_node;
    }

    void ParaTreeModel::buildSunTreeModel(QSharedPointer<Sun> sun)
    {
        // position
        auto position_node =
            createNode(root_node, "position", ""); // 这个节点不可更改，只是用来放子节点的父节点

        auto sun_position_ptr = SOLAR_GET_VALUE(Sun, sun_position_, *sun);

        // position-azimuth
        QVariant azimuth = SOLAR_GET_VALUE(SunPosition, azimuth_, *sun_position_ptr);
        createNode(position_node, "azimuth", azimuth, EDITABLE);

        // position-elevation
        QVariant elevation = SOLAR_GET_VALUE(SunPosition, elevation_, *sun_position_ptr);
        createNode(position_node, "elevation", elevation, EDITABLE);

        // position-dni
        QVariant dni = SOLAR_GET_VALUE(SunPosition, dni_, *sun_position_ptr);
        createNode(position_node, "dni", dni, EDITABLE);

        // position-trackable
        QVariant trackable = SOLAR_GET_VALUE(SunPosition, trackable_, *sun_position_ptr);
        createNode(position_node, "trackable", trackable, EDITABLE);

        // sunshape
        auto sun_shape_ptr = SOLAR_GET_VALUE(Sun, sunshape_, *sun);
        SunShapeType current_sunshape_type = sun_shape_ptr->getType();
        // auto sunshape = std::any_cast< boost::unordered::unordered_flat_map<SunShapeType,
        // std::shared_ptr<SunShape>> >
        //                 (solar::getParaAsAny(toMemberName("sunshape"),sun.get()));
        // SunShapeType current_sunshape_type =
        // std::any_cast<SunShapeType>(solar::getParaAsAny(toMemberName("sunshape_type"),
        // sun.get())); SunShapeType current_sunshape_type =
        // solar::getPara(toMemberName("sunshape_type"), sun.get()).value<SunShapeType>();
        QString current_option;
        switch (current_sunshape_type)
        {
        case SunShapeType::kSunShapeBuie:
            current_option = "Buie";
            break;
        case SunShapeType::kSunShapeGaussian:
            current_option = "Gaussian";
            break;
        case SunShapeType::kSunShapePillbox:
            current_option = "Pillbox";
            break;
        }

        auto sunshape_node = createNode(root_node, "sunshape", current_option, OPTIONAL);

        QList<QString> options;
        options.append("Buie");
        options.append("Gaussian");
        options.append("Pillbox");
        sunshape_node->initOptions(options);

        // ！！！这里添加option_child时，一定要格外留意是否选中当前的选项

        // sunshape-csr
        // auto buie_sunshape = sunshape[kSunShapeBuie];
        if (current_sunshape_type == SunShapeType::kSunShapeBuie)
        {
            QVariant csr = sun_shape_ptr->getPara();
            createNode(sunshape_node, "csr", csr, EDITABLE, true, "Buie");
        }
        else
        {
            QVariant csr = 0.02;
            createNode(sunshape_node, "csr", csr, EDITABLE, false, "Buie");
        }

        // sunshape-theta_max
        if (current_sunshape_type == SunShapeType::kSunShapePillbox)
        {
            QVariant theta_max = sun_shape_ptr->getPara();
            createNode(sunshape_node, "theta_max", theta_max, EDITABLE, true, "Pillbox");
        }
        else
        {
            QVariant theta_max = 0.00465;
            createNode(sunshape_node, "theta_max", theta_max, EDITABLE, false, "Pillbox");
        }

        // sunshape-gaussian
        if (current_sunshape_type == SunShapeType::kSunShapeGaussian)
        {
            QVariant sigma = sun_shape_ptr->getPara();
            createNode(sunshape_node, "sigma", sigma, EDITABLE, true, "Gaussian");
        }
        else
        {
            QVariant sigma = 0.00251;
            createNode(sunshape_node, "sigma", sigma, EDITABLE, false, "Gaussian");
        }
    }

    void ParaTreeModel::buildLocationTreeModel(QSharedPointer<Location> location)
    {
        // site_name
        QVariant site = QString::fromStdString(SOLAR_GET_VALUE(Location, site_name_, *location));
        createNode(root_node, "site_name", site, EDITABLE);
        // qDebug() << "-----------Location site_name="<<site;

        // longitude
        QVariant longitude = SOLAR_GET_VALUE(Location, longitude_, *location);
        createNode(root_node, "longitude", longitude, EDITABLE);

        // latitude
        QVariant latitude = SOLAR_GET_VALUE(Location, latitude_, *location);
        createNode(root_node, "latitude", latitude, EDITABLE);
    }

    void ParaTreeModel::buildAirTreeModel(QSharedPointer<Air> air)
    {
        auto attenuation_ptr = SOLAR_GET_VALUE(Air, attenuation_, *air);
        AttenuationType currrent_attenuation_type = attenuation_ptr->getType();
        // auto attenuation = std::any_cast<boost::unordered::unordered_flat_map<AttenuationType,
        // std::shared_ptr<Attenuation>> >
        //                     (solar::getParaAsAny(toMemberName("attenuation"), air.get()));

        // AttenuationType currrent_attenuation_type =
        // std::any_cast<AttenuationType>(solar::getParaAsAny(toMemberName("attenuation_type"),
        // air.get())); AttenuationType currrent_attenuation_type =
        // solar::getPara(toMemberName("attenuation_type"), air.get()).value<AttenuationType>();
        QString current_option;
        switch (currrent_attenuation_type)
        {
        case AttenuationType::kAttenuationVacuum:
            current_option = "Vacuum";
            break;
        case AttenuationType::kAttenuationCustom:
            current_option = "Custom";
            break;
        case AttenuationType::kAttenuationExponential:
            current_option = "Exponential";
            break;
        }

        auto attenuation_node = createNode(root_node, "attenuation", current_option, OPTIONAL);
        QList<QString> options;
        options.append("Vacuum");
        options.append("Custom");
        options.append("Exponential");
        attenuation_node->initOptions(options);

        // 添加三个option_child
        // 由于暂时 vacuum、custom没有孩子节点，因此暂时只添加exponential的孩子节点
        if (currrent_attenuation_type == AttenuationType::kAttenuationExponential)
        {
            QVariant beta = attenuation_ptr->getPara();
            createNode(attenuation_node, "beta", beta, EDITABLE, true, "Exponential");
        }
        else
        {
            QVariant beta = 0.11;
            createNode(attenuation_node, "beta", beta, EDITABLE, false, "Exponential");
        }
    }
    void ParaTreeModel::buildTerrainTreeModel(QSharedPointer<Terrain> terrain)
    {
        // dem_file_
        // QVariant dem_file =
        // QString(terrain->getPara(toMemberName("dem_file")).value<std::string>().c_str());
        QVariant dem_file = QString::fromStdString(SOLAR_GET_VALUE(Terrain, dem_file_, *terrain));
        createNode(root_node, "dem_file", dem_file, EDITABLE);
        qDebug() << "-----------Terrain dem_file=" << dem_file.toString();
    }

    void ParaTreeModel::buildCameraTreeModel(QSharedPointer<Camera> camera)
    {
        // position
        // QVariant position = camera->getPara(toMemberName("position"));
        QVariant position = solar::getPara(toMemberName("position"), camera.get());
        createNode(root_node, "position", QString::fromStdString(position.value<Vec3>().toString()),
                   EDITABLE);
        // qDebug() << "-----------Camera
        // position="<<QString::fromStdString(position.value<Vec3>().toString());

        // rotation
        // QVariant rotation = camera->getPara(toMemberName("rotation"));

        // QVariant axis = rotation.getPara(toMemberName("axis"));
        // QVariant angle = rotation.getPara(toMemberName("angle"));       // Vec3的如何设置？？？？
        createNode(root_node, "rotation",
                   QString::fromStdString((SOLAR_GET_VALUE(Camera, rotation_, *camera)).toString()),
                   EDITABLE);
        // qDebug() << "-----------Camera rotation=" <<
        // QString::fromStdString(rotation.value<Rotation>().toString()); perspective QVariant
        // perspective = camera->getPara(toMemberName("perspective"));
        createNode(root_node, "perspective", SOLAR_GET_VALUE(Camera, perspective_, *camera),
                   EDITABLE);
    }

    void ParaTreeModel::buildCloudTreeModel(QSharedPointer<Cloud> cloud)
    {
        // auto grid_ptr = cloud->getPara(toMemberName("grid")).value<std::shared_ptr<Grid>>();
        // qDebug() << "cloud-1";
        /**
         * BUG::it is invalid to use std::any_cast to change std::any to Grid*
         *
         */
        /*
         // auto grid_ptr =
         std::any_cast<Grid*>(solar::getParaPtr(toMemberName("grid"),cloud.get())); auto grid_ptr =
         solar::getPara(toMemberName("grid"), cloud.get()).value<std::shared_ptr<Grid>>();
         // qDebug() << "cloud_2";
         auto grid_node = createNode(root_node, "grid", "");

         // grid_
         QVariant grid = solar::getPara(toMemberName("grid"), grid_ptr.get());
         createNode(grid_node, "grid",grid, EDITABLE);

         // fill
         QVariant fill = solar::getPara(toMemberName("fill"), grid_ptr.get());
         createNode(grid_node, "fill",fill, EDITABLE);

         // steps
         QVariant steps = solar::getPara(toMemberName("steps"), grid_ptr.get());
         createNode(grid_node, "steps",QString::fromStdString(steps.value<Vec3>().toString()),
         EDITABLE);

         // divisions
         QVariant divisions = solar::getPara(toMemberName("divisions"), grid_ptr.get());
         createNode(grid_node,
         "divisions",QString::fromStdString(divisions.value<Vec3>().toString()), EDITABLE);

         // min
         QVariant min = solar::getPara(toMemberName("min"), grid_ptr.get());
         createNode(grid_node, "min",QString::fromStdString(min.value<Vec3>().toString()),
         EDITABLE);

         // max
         QVariant max = solar::getPara(toMemberName("max"), grid_ptr.get());
         createNode(grid_node, "max",QString::fromStdString(max.value<Vec3>().toString()),
         EDITABLE);
         */
        // file
        createNode(root_node, "cloud_file",
                   QString::fromStdString(SOLAR_GET_VALUE(Cloud, cloud_file_, *cloud)), EDITABLE);
        qDebug() << "-----------Cloud file=" << SOLAR_GET_VALUE(Cloud, cloud_file_, *cloud);
    }
    void ParaTreeModel::buildNodeTreeModel(QSharedPointer<Node> node)
    {
        // translation
        createNode(root_node, "translation",
                   QString::fromStdString((SOLAR_GET_VALUE(Node, translation_, *node)).toString()),
                   EDITABLE);

        // rotation
        createNode(root_node, "rotation",
                   QString::fromStdString((SOLAR_GET_VALUE(Node, rotation_, *node)).toString()),
                   EDITABLE);

        // scale
        createNode(root_node, "scale",
                   QString::fromStdString((SOLAR_GET_VALUE(Node, scale_, *node)).toString()),
                   EDITABLE);
    }

    /**
     * 问题： 每增加一种geometry类型，这里就需要增加一列option_child的添加，过于臃肿
     * 是否可以把添加option chaild node的过程写到每个geometry的具体类里
     * 类似的，前面的optional节点的孩子也可以用同样方法添加
     *
     * 先写着,写其中一两种简单的geometry
     */
    /**
     * TODO:: add more kinds of geometry
     */
    void ParaTreeModel::buildHeliostatTreeModel(QSharedPointer<Heliostat> heliostat)
    {
        // id
        // Heliostat::heilostat_cnt_ ++ ;
        createNode(root_node, "id", SOLAR_GET_VALUE(Heliostat, id_, *heliostat));

        // subhelio_row_col
        createNode(root_node, "subhelio_row_col",
                   QString::fromStdString(
                       (SOLAR_GET_VALUE(Heliostat, subhelio_row_col_, *heliostat)).toString()),
                   EDITABLE);

        // gap
        createNode(
            root_node, "gap",
            QString::fromStdString((SOLAR_GET_VALUE(Heliostat, gap_, *heliostat)).toString()),
            EDITABLE);

        /**
         * geometry
         */
        auto geometry_ptr = SOLAR_GET_VALUE(Heliostat, geometry_, *heliostat);
        GeometryType current_geometry_type = geometry_ptr->getType();
        // auto geometry = std::any_cast< boost::unordered::unordered_flat_map<GeometryType,
        // std::shared_ptr<Geometry>> >
        //                 (solar::getParaAsAny(toMemberName("geometry"),heliostat.get()));
        // GeometryType current_geometry_type =
        // std::any_cast<GeometryType>(solar::getParaAsAny(toMemberName("geometry_type"),heliostat.get()));
        // GeometryType current_geometry_type =
        // solar::getPara(toMemberName("geometry_type"),heliostat.get()).value<GeometryType>();
        QString current_geometry_option = "";
        switch (current_geometry_type)
        {
        case GeometryType::kGeometryRectangle:
            current_geometry_option = "Rectangle";
            break;
        case GeometryType::kGeometryParabolic:
            current_geometry_option = "Parabolic";
            break;
        case GeometryType::kGeometryBSpline:
            current_geometry_option = "BSpline";
            break;
        case GeometryType::kGeometryMesh:
            current_geometry_option = "Mesh";
            break;
        }
        auto geometry_node = createNode(root_node, "geometry", current_geometry_option, OPTIONAL);
        QList<QString> geometry_options;
        geometry_options.append("Rectangle");
        geometry_options.append("Parabolic");
        geometry_options.append("BSpline");
        geometry_options.append("Mesh");
        geometry_node->initOptions(geometry_options);

        // option--Rectangle
        if (current_geometry_type == GeometryType::kGeometryRectangle)
        {
            auto rectangle_geometry_ptr = std::dynamic_pointer_cast<Rectangle>(geometry_ptr);
            createNode(geometry_node, "size",
                       QString::fromStdString(
                           (SOLAR_GET_VALUE(Rectangle, size_, *rectangle_geometry_ptr)).toString()),
                       EDITABLE, true, "Rectangle");
        }
        else
        {
            Vec2 size(1, 1);
            createNode(geometry_node, "size", QString::fromStdString(size.toString()), EDITABLE,
                       false, "Rectangle");
        }

        // option--Parabolic
        if (current_geometry_type == GeometryType::kGeometryParabolic)
        {
            auto parabolic_geometry_ptr = std::dynamic_pointer_cast<Parabolic>(geometry_ptr);

            createNode(geometry_node, "a",
                       QString::fromStdString(solar::toString(
                           SOLAR_GET_VALUE(Parabolic, a_, *parabolic_geometry_ptr))),
                       EDITABLE, true, "Parabolic");
            createNode(geometry_node, "b",
                       QString::fromStdString(solar::toString(
                           SOLAR_GET_VALUE(Parabolic, b_, *parabolic_geometry_ptr))),
                       EDITABLE, true, "Parabolic");
            createNode(geometry_node, "size",
                       QString::fromStdString(solar::toString(
                           SOLAR_GET_VALUE(Parabolic, size_, *parabolic_geometry_ptr))),
                       EDITABLE, true, "Parabolic");
        }
        else
        {
            double a = 1;
            createNode(geometry_node, "a", QString::fromStdString(solar::toString(a)), EDITABLE,
                       false, "Parabolic");
            double b = 1;
            createNode(geometry_node, "b", QString::fromStdString(solar::toString(b)), EDITABLE,
                       false, "Parabolic");
            Vec2 size(1, 1);
            createNode(geometry_node, "size", QString::fromStdString(solar::toString(size)),
                       EDITABLE, false, "Parabolic");
        }

        // option--BSpline
        if (current_geometry_type == GeometryType::kGeometryBSpline)
        {
            auto bspline_geometry_ptr = std::dynamic_pointer_cast<BSpline>(geometry_ptr);
            createNode(
                geometry_node, "file",
                QString::fromStdString(SOLAR_GET_VALUE(BSpline, file_, *bspline_geometry_ptr)),
                EDITABLE, true, "BSpline");
        }
        else
        {
            QString file = "";
            createNode(geometry_node, "file", file, EDITABLE, false, "BSpline");
        }

        // option--Mesh
        if (current_geometry_type == GeometryType::kGeometryMesh)
        {
            auto mesh_geometry_ptr = std::dynamic_pointer_cast<Mesh>(geometry_ptr);
            createNode(geometry_node, "file",
                       QString::fromStdString(SOLAR_GET_VALUE(Mesh, file_, *mesh_geometry_ptr)),
                       EDITABLE, true, "Mesh");
        }
        else
        {
            QString file = "";
            createNode(geometry_node, "file", file, EDITABLE, false, "Mesh");
        }

        /**
         * material
         */
        // heliostat没有absorb这一选项
        // material
        auto material_ptr = SOLAR_GET_VALUE(Heliostat, material_, *heliostat);
        MaterialType current_material_type = material_ptr->getType();
        // auto material = std::any_cast< boost::unordered::unordered_flat_map<MaterialType,
        // std::shared_ptr<Material>> >
        //                 (solar::getParaAsAny(toMemberName("material"),heliostat.get()));
        // MaterialType current_material_type = solar::getPara(toMemberName("material_type"),
        // heliostat.get()).value<MaterialType>();
        QString current_material_option = "";
        switch (current_material_type)
        {
        case MaterialType::kMaterialReflect:
            current_material_option = "Reflect";
            break;
        case MaterialType::kMaterialRefract:
            current_material_option = "Refract";
            break;
        }

        auto material_node = createNode(root_node, "material", current_material_option, OPTIONAL);
        QList<QString> material_options;
        material_options.append("Reflect");
        material_options.append("Refract");
        material_node->initOptions(material_options);

        // option-reflect
        if (current_material_type == MaterialType::kMaterialReflect)
        {
            auto reflect_material_ptr = std::dynamic_pointer_cast<Reflect>(material_ptr);
            createNode(material_node, "reflectivity",
                       SOLAR_GET_VALUE(Reflect, reflectivity_, *reflect_material_ptr), EDITABLE,
                       true, "Reflect");
            auto slope_error_type =
                SOLAR_GET_VALUE(Reflect, slope_error_type_, *reflect_material_ptr);
            QString slope_error_type_string =
                slope_error_type == SlopeErrorType::kGaussianSlopeError ? "Gaussian" : "Pillbox";
            auto slope_error_type_node =
                createNode(material_node, "slope_error_type", slope_error_type_string, OPTIONAL,
                           true, "Reflect");
            QList<QString> slopeerror_options;
            slopeerror_options.append("Gaussian");
            slopeerror_options.append("Pillbox");
            slope_error_type_node->initOptions(slopeerror_options);

            createNode(material_node, "slope",
                       SOLAR_GET_VALUE(Reflect, slope_, *reflect_material_ptr), EDITABLE, true,
                       "Reflect");
        }
        else
        {
            QVariant reflectivity = 0.88;
            createNode(material_node, "reflectivity", reflectivity, EDITABLE, false, "Reflect");
            SlopeErrorType slope_error_type = SlopeErrorType::kGaussianSlopeError;
            QString slope_error_type_string =
                slope_error_type == SlopeErrorType::kGaussianSlopeError ? "Gaussian" : "Pillbox";
            auto slope_error_type_node =
                createNode(material_node, "slope_error_type", slope_error_type_string, OPTIONAL,
                           false, "Reflect");
            QList<QString> slopeerror_options;
            slopeerror_options.append("Gaussian");
            slopeerror_options.append("Pillbox");
            slope_error_type_node->initOptions(slopeerror_options);

            QVariant slope = 0.02;
            createNode(material_node, "slope", slope, EDITABLE, false, "Reflect");
        }

        // option-refract
        if (current_material_type == MaterialType::kMaterialRefract)
        {
            auto refract_material_ptr = std::dynamic_pointer_cast<Refract>(material_ptr);
            createNode(material_node, "transmissivity",
                       SOLAR_GET_VALUE(Refract, transmissivity_, *refract_material_ptr), EDITABLE,
                       true, "Refract");
            createNode(material_node, "air_refractive_index",
                       SOLAR_GET_VALUE(Refract, air_refractive_index_, *refract_material_ptr),
                       EDITABLE, true, "Refract");
            createNode(material_node, "glass_refractive_index",
                       SOLAR_GET_VALUE(Refract, glass_refractive_index_, *refract_material_ptr),
                       EDITABLE, true, "Refract");
            createNode(material_node, "glass_thickness",
                       SOLAR_GET_VALUE(Refract, glass_thickness_, *refract_material_ptr), EDITABLE,
                       true, "Refract");

            SlopeErrorType slope_error_type =
                SOLAR_GET_VALUE(Refract, slope_error_type_, *refract_material_ptr);
            QString slope_error_type_string =
                slope_error_type == SlopeErrorType::kGaussianSlopeError ? "Gaussian" : "Pillbox";
            auto slope_error_type_node =
                createNode(material_node, "slope_error_type", slope_error_type_string, OPTIONAL,
                           true, "Refract");
            QList<QString> slopeerror_options;
            slopeerror_options.append("Gaussian");
            slopeerror_options.append("Pillbox");
            slope_error_type_node->initOptions(slopeerror_options);

            createNode(material_node, "slope",
                       SOLAR_GET_VALUE(Refract, slope_, *refract_material_ptr), EDITABLE, true,
                       "Refract");
        }
        else
        {
            // QVariant reflectivity = 0.88;
            // createNode(material_node,"reflectivity",reflectivity,EDITABLE,false,"Refract");
            QVariant transmissivity = 0.1;
            createNode(material_node, "transmissivity", transmissivity, EDITABLE, false, "Refract");
            QVariant air_refractive_index = 1.0;
            createNode(material_node, "air_refractive_index", air_refractive_index, EDITABLE, false,
                       "Refract");
            QVariant glass_refractive_index = 1.5;
            createNode(material_node, "glass_refractive_index", glass_refractive_index, EDITABLE,
                       false, "Refract");
            QVariant glass_thickness = 0.5;
            createNode(material_node, "glass_thickness", glass_thickness, EDITABLE, false,
                       "Refract");

            SlopeErrorType slope_error_type = SlopeErrorType::kGaussianSlopeError;
            QString slope_error_type_string =
                slope_error_type == SlopeErrorType::kGaussianSlopeError ? "Gaussian" : "Pillbox";
            auto slope_error_type_node =
                createNode(material_node, "slope_error_type", slope_error_type_string, OPTIONAL,
                           false, "Refract");
            QList<QString> slopeerror_options;
            slopeerror_options.append("Gaussian");
            slopeerror_options.append("Pillbox");
            slope_error_type_node->initOptions(slopeerror_options);

            QVariant slope = 0.02;
            createNode(material_node, "slope", slope, EDITABLE, false, "Refract");
        }

        createNode(root_node, "thickness", SOLAR_GET_VALUE(Heliostat, thickness_, *heliostat),
                   EDITABLE);

        createNode(root_node, "has_brace", SOLAR_GET_VALUE(Heliostat, has_brace_, *heliostat),
                   EDITABLE);

        /*
            ！！！！！力学参数这里写得有问题，以后再改吧
        */
        // 力学参数
        // auto mechanical_para_ptr =
        // heliostat->getPara(toMemberName("mechanical_para")).value<std::shared_ptr<MechanicalPara>>();
        // auto mechanical_para_node = createNode(root_node,"mechanical_para","");
        // QVariant density = mechanical_para_ptr->getPara(toMemberName("density"));
        // createNode(mechanical_para_node,"density",density,EDITABLE);
        // QVariant elastic_modulus = mechanical_para_ptr->getPara(toMemberName("elastic_modulus"));
        // createNode(mechanical_para_node,"elastic_modulus",elastic_modulus,EDITABLE);
    }

    /**
     * material固定为absorb
     */
    /**
     * TODO: add geometry type: refined rectangle, refined cylinder
     */
    void ParaTreeModel::buildReceiverTreeModel(QSharedPointer<Receiver> receiver)
    {
        // id
        auto id = SOLAR_GET_VALUE(Receiver, id_, *receiver);
        createNode(root_node, "id", id);

        /**
         * geometry
         */
        auto geometry_ptr = SOLAR_GET_VALUE(Receiver, geometry_, *receiver);
        GeometryType current_geometry_type = geometry_ptr->getType();
        // auto geometry = std::any_cast< boost::unordered::unordered_flat_map<GeometryType,
        // std::shared_ptr<Geometry>> >
        //                 (solar::getParaAsAny(toMemberName("geometry"), receiver.get()));
        // GeometryType current_geometry_type = solar::getPara(toMemberName("geometry_type"),
        // receiver.get()).value<GeometryType>();

        QString current_geometry_option = "";
        switch (current_geometry_type)
        {
        case GeometryType::kGeometryRectangle:
            current_geometry_option = "Rectangle";
            break;
        case GeometryType::kGeometryCylinder:
            current_geometry_option = "Cylinder";
            break;
        case GeometryType::kGeometryRefinedRectangle:
            current_geometry_option = "RefinedRectangle";
            break;
        case GeometryType::kGeometryRefinedCylinder:
            current_geometry_option = "RefinedCylinder";
            break;
            // case kGeometryMultiPanel:
            //     current_geometry_option="MultiPanel"; break;
        }
        auto geometry_node = createNode(root_node, "geometry", current_geometry_option, OPTIONAL);
        QList<QString> geometry_options;
        geometry_options.append("Rectangle");
        geometry_options.append("Cylinder");
        geometry_options.append("RefinedRectangle");
        geometry_options.append("RefinedCylinder");
        // geometry_options.append("MultiPanel");
        geometry_node->initOptions(geometry_options);

        // option--Rectangle
        if (current_geometry_type == GeometryType::kGeometryRectangle)
        {
            auto rectangle_geometry_ptr = std::dynamic_pointer_cast<Rectangle>(geometry_ptr);
            createNode(geometry_node, "size",
                       QString::fromStdString(solar::toString(
                           SOLAR_GET_VALUE(Rectangle, size_, *rectangle_geometry_ptr))),
                       EDITABLE, true, "Rectangle");
        }
        else
        {
            Vec2 size(1, 1);
            createNode(geometry_node, "size", QString::fromStdString(size.toString()), EDITABLE,
                       false, "Rectangle");
        }

        // option--Cylinder
        if (current_geometry_type == GeometryType::kGeometryCylinder)
        {
            auto cylinder_geometry_ptr = std::dynamic_pointer_cast<Cylinder>(geometry_ptr);
            createNode(geometry_node, "height",
                       SOLAR_GET_VALUE(Cylinder, height_, *cylinder_geometry_ptr), EDITABLE, true,
                       "Cylinder");
            createNode(geometry_node, "radius",
                       SOLAR_GET_VALUE(Cylinder, radius_, *cylinder_geometry_ptr), EDITABLE, true,
                       "Cylinder");
        }
        else
        {
            QVariant height = 1;
            createNode(geometry_node, "height", height, EDITABLE, false, "Cylinder");
            QVariant radius = 1;
            createNode(geometry_node, "radius", radius, EDITABLE, false, "Cylinder");
        }

        /**
         * TODO: add detailed attributes of refined rectangle, refined cylinder, multipanel
         */
        // option--RefinedRectangle
        if (current_geometry_type == GeometryType::kGeometryRefinedRectangle)
        {
            auto refinedrectangle_geometry_ptr =
                std::dynamic_pointer_cast<RefinedRectangle>(geometry_ptr);
            createNode(geometry_node, "size",
                       QString::fromStdString(solar::toString(SOLAR_GET_VALUE(
                           RefinedRectangle, size_, *refinedrectangle_geometry_ptr))),
                       EDITABLE, true, "RefinedRectangle");
            createNode(
                geometry_node, "tube_radius",
                SOLAR_GET_VALUE(RefinedRectangle, tube_radius_, *refinedrectangle_geometry_ptr),
                EDITABLE, true, "RefinedRectangle");
        }
        else
        {
            Vec2 size(1, 1);
            createNode(geometry_node, "size", QString::fromStdString(size.toString()), EDITABLE,
                       false, "RefinedRectangle");
            double tube_radius = 0.01105;
            createNode(geometry_node, "tube_radius", tube_radius, EDITABLE, false,
                       "RefinedRectangle");
        }

        // option--RefinedCylinder
        if (current_geometry_type == GeometryType::kGeometryRefinedCylinder)
        {
            auto refinedcylinder_geometry_ptr =
                std::dynamic_pointer_cast<RefinedCylinder>(geometry_ptr);
            createNode(geometry_node, "height",
                       SOLAR_GET_VALUE(RefinedCylinder, height_, *refinedcylinder_geometry_ptr),
                       EDITABLE, true, "RefinedCylinder");
            createNode(geometry_node, "radius",
                       SOLAR_GET_VALUE(RefinedCylinder, radius_, *refinedcylinder_geometry_ptr),
                       EDITABLE, true, "RefinedCylinder");

            createNode(
                geometry_node, "tube_radius",
                SOLAR_GET_VALUE(RefinedCylinder, tube_radius_, *refinedcylinder_geometry_ptr),
                EDITABLE, true, "RefinedCylinder");
            createNode(geometry_node, "tube",
                       SOLAR_GET_VALUE(RefinedCylinder, tube_, *refinedcylinder_geometry_ptr),
                       EDITABLE, true, "RefinedCylinder");
            createNode(geometry_node, "tube_unit",
                       SOLAR_GET_VALUE(RefinedCylinder, tube_unit_, *refinedcylinder_geometry_ptr),
                       EDITABLE, true, "RefinedCylinder");
            createNode(geometry_node, "panel",
                       SOLAR_GET_VALUE(RefinedCylinder, panel_, *refinedcylinder_geometry_ptr),
                       EDITABLE, true, "RefinedCylinder");
        }
        else
        {
            QVariant height = 1;
            createNode(geometry_node, "height", height, EDITABLE, false, "RefinedCylinder");
            QVariant radius = 1;
            createNode(geometry_node, "radius", radius, EDITABLE, false, "RefinedCylinder");

            QVariant tube_radius = 0.01105;
            createNode(geometry_node, "tube_radius", tube_radius, EDITABLE, false,
                       "RefinedCylinder");
            QVariant tube = 62;
            createNode(geometry_node, "tube", tube, EDITABLE, false, "RefinedCylinder");
            QVariant tube_unit = 20;
            createNode(geometry_node, "tube_unit", tube_unit, EDITABLE, false, "RefinedCylinder");
            QVariant panel = 18;
            createNode(geometry_node, "panel", panel, EDITABLE, false, "RefinedCylinder");
        }

        // // option--MultiPanel
        // if(current_geometry_type == GeometryType::kGeometryMultiPanel)
        // {
        //     // QVariant height = geometry_ptr->getPara(toMemberName("height"));
        //     // createNode(geometry_node,"height", height,EDITABLE,true,"MultiPanel");
        //     // QVariant radius = geometry_ptr->getPara(toMemberName("radius"));
        //     // createNode(geometry_node,"radius", radius,EDITABLE,true,"MultiPanel");
        //     QVariant size = geometry_ptr->getPara(toMemberName("size"));
        //     createNode(geometry_node, "size",
        //     QString::fromStdString(size.value<Vec2>().toString()), EDITABLE, true, "MultiPanel");

        //     QVariant tube_radius = geometry_ptr->getPara(toMemberName("tube_radius"));
        //     createNode(geometry_node, "tube_radius", tube_radius, EDITABLE, true,"MultiPanel");
        //     QVariant tube = geometry_ptr->getPara(toMemberName("tube"));
        //     createNode(geometry_node, "tube", tube, EDITABLE, true,"MultiPanel");
        //     QVariant tube_unit = geometry_ptr->getPara(toMemberName("tube_unit"));
        //     createNode(geometry_node, "tube_unit",tube_unit, EDITABLE, true,"MultiPanel");
        //     QVariant panel = geometry_ptr->getPara(toMemberName("panel"));
        //     createNode(geometry_node, "panel", panel, EDITABLE, true,"MultiPanel");

        // }
        // else{
        //     // QVariant height = 1 ;
        //     // createNode(geometry_node,"height", height,EDITABLE,false,"MultiPanel");
        //     // QVariant radius = 1 ;
        //     // createNode(geometry_node,"radius", radius,EDITABLE,false,"MultiPanel");
        //     Vec2 size(1,1);
        //     createNode(geometry_node, "size", QString::fromStdString(size.toString()), EDITABLE,
        //     false, "MultiPanel");

        //     QVariant tube_radius = 0.01105;
        //     createNode(geometry_node, "tube_radius",tube_radius, EDITABLE, false,"MultiPanel");
        //     QVariant tube = 62;
        //     createNode(geometry_node, "tube",tube, EDITABLE, false,"MultiPanel");
        //     QVariant tube_unit = 20;
        //     createNode(geometry_node, "tube_unit",tube_unit, EDITABLE, false,"MultiPanel");
        //     QVariant panel = 18;
        //     createNode(geometry_node, "panel", panel, EDITABLE, false,"MultiPanel");
        // }

        /**
         * material
         */
        // auto material_ptr =
        // receiver->getPara(toMemberName("material")).value<std::shared_ptr<Material>>();
        // MaterialType current_material_type = material_ptr->getType();
        auto material_ptr = SOLAR_GET_VALUE(Receiver, material_, *receiver);

        QString current_material_option = "Absorb";
        auto material_node =
            createNode(root_node, "material",
                       current_material_option); //!!!因为只有一个选项，因此设置为不可选也不可编辑
        auto absorb_material_ptr = std::dynamic_pointer_cast<Absorb>(material_ptr);
        createNode(material_node, "absorptivity",
                   SOLAR_GET_VALUE(Absorb, absorptivity_, *absorb_material_ptr), EDITABLE);
    }

    /**
     * TODO:: add more kinds of geometries and materials
     */
    void ParaTreeModel::buildOrdinaryTreeModel(QSharedPointer<Ordinary> ordinary)
    {
        auto geometry_ptr = solar::getPara(toMemberName("geometry"), ordinary.get())
                                .value<std::shared_ptr<Geometry>>();
        GeometryType current_geometry_type = geometry_ptr->getType();
        // qDebug() <<"buildOrdinaryTreeModel";
        // auto geometry = std::any_cast< boost::unordered::unordered_flat_map<GeometryType,
        // std::shared_ptr<Geometry>> >
        //                 (solar::getParaAsAny(toMemberName("geometry"), ordinary.get()));
        // qDebug() <<"buildOrdinaryTreeModel - 1";

        // GeometryType current_geometry_type = solar::getPara(toMemberName("geometry_type"),
        // ordinary.get()).value<GeometryType>(); qDebug() <<"buildOrdinaryTreeModel - 2";

        QString current_geometry_option = "";
        switch (current_geometry_type)
        {
        case GeometryType::kGeometryCylinder:
            current_geometry_option = "Cylinder";
            break;
        case GeometryType::kGeometryRectangle:
            current_geometry_option = "Rectangle";
            break;
        }
        auto geometry_node = createNode(root_node, "geometry", current_geometry_option, OPTIONAL);
        QList<QString> geometry_options;
        geometry_options.append("Cylinder");
        geometry_options.append("Rectangle");
        geometry_node->initOptions(geometry_options);
        // qDebug() <<"buildOrdinaryTreeModel - 3";

        // option--Cylinder
        if (current_geometry_type == GeometryType::kGeometryCylinder)
        {

            auto cylinder_geometry_ptr = std::dynamic_pointer_cast<Cylinder>(geometry_ptr);
            createNode(geometry_node, "height",
                       SOLAR_GET_VALUE(Cylinder, height_, *cylinder_geometry_ptr), EDITABLE, true,
                       "Cylinder");
            createNode(geometry_node, "radius",
                       SOLAR_GET_VALUE(Cylinder, radius_, *cylinder_geometry_ptr), EDITABLE, true,
                       "Cylinder");
        }
        else
        {
            QVariant height = 1;
            createNode(geometry_node, "height", height, EDITABLE, false, "Cylinder");
            QVariant radius = 1;
            createNode(geometry_node, "radius", radius, EDITABLE, false, "Cylinder");
        }
        qDebug() << "buildOrdinaryTreeModel - 4";

        // option--Rectangle
        if (current_geometry_type == GeometryType::kGeometryRectangle)
        {
            auto rectangle_geometry_ptr = std::dynamic_pointer_cast<Rectangle>(geometry_ptr);
            createNode(geometry_node, "size",
                       QString::fromStdString(solar::toString(
                           SOLAR_GET_VALUE(Rectangle, size_, *rectangle_geometry_ptr))),
                       EDITABLE, true, "Rectangle");
        }
        else
        {
            Vec2 size(1, 1);
            createNode(geometry_node, "size", QString::fromStdString(size.toString()), EDITABLE,
                       false, "Rectangle");
        }
        qDebug() << "buildOrdinaryTreeModel - 5";
    }

    /*
------------------------------------------------------------------------------
*/

    auto ParaTreeModel::columnCount(const QModelIndex& parent) const -> int // 返回列数
    {
        return 2;
    }
    auto ParaTreeModel::rowCount(const QModelIndex& parent) const -> int // 返回孩子节点的个数
    {
        int ret = 0;
        // QModelIndex代表的是一个Item，不是一个Row
        if (parent.column() >
            0) // 这里是因为所有的孩子节点都是放在column=0上面的，当column>0时，默认是没有节点的
        {
            // qDebug() << "1111 " << parent.column();
            return 0;
        }

        if (!parent.isValid())
        {
            // qDebug() << "2222";
            ret = root_node->childCount();
        }
        else
        {
            // qDebug() << "3333";
            //  这里使用普通指针
            auto* parent_node = static_cast<ParaTreeNode*>(parent.internalPointer());
            ret = parent_node->childCount();
        }

        return ret;
    }
    auto ParaTreeModel::roleNames() const -> QHash<int, QByteArray> { return this->role_names_; }
    auto ParaTreeModel::data(const QModelIndex& index, int role) const -> QVariant
    {
        if (!index.isValid())
        {
            return {};
        }

        switch (role)
        {
        case NAME:
        {
            return static_cast<ParaTreeNode*>(index.internalPointer())->data(0);
        }
        case PARA:
        {
            return static_cast<ParaTreeNode*>(index.internalPointer())->data(1);
        }
        }
        return {};
    }
    auto ParaTreeModel::flags(const QModelIndex& index) const -> Qt::ItemFlags
    {
        if (!index.isValid())
        {
            return Qt::NoItemFlags;
        }

        return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable;
    }
    auto ParaTreeModel::index(int row, int column, const QModelIndex& parent) const -> QModelIndex
    {
        if (!hasIndex(row, column, parent))
        {
            return {};
        }

        ParaTreeNode* parent_node = nullptr;
        if (!parent.isValid())
        {
            parent_node = root_node.get();
        }
        else
        {
            parent_node = static_cast<ParaTreeNode*>(parent.internalPointer());
        }

        ParaTreeNode* child_node = (parent_node->child(row)).get();
        if (child_node != nullptr)
        {
            return createIndex(row, column, child_node);
        }

        return {};
    }
    auto ParaTreeModel::parent(const QModelIndex& index) const -> QModelIndex
    {
        if (!index.isValid())
        {
            return {};
        }

        auto* child_node = static_cast<ParaTreeNode*>(index.internalPointer());
        auto parent_node = child_node->parent();

        if (parent_node == root_node)
        {
            return {};
        }
        // !!!!!注意一下，这里的row()是否能返回正确的值
        return createIndex(parent_node->row(), 0, parent_node.get());
    }
    auto ParaTreeModel::getRootNode() const -> QSharedPointer<ParaTreeNode> { return root_node; }
    /**
     * ===========================set Node Para============================================
     */

    // ！！！！！！！！注意：不要忘记更新para中的内容！！！！！
    // ！！！！！！！问题：：para中记录的属性如何更新？？？如果是editable，直接setPara即可，如果是optional，如何做？？？
    /**
     * ！！！！！！！需要修改
     */
    void ParaTreeModel::setNodePara(QModelIndex index,
                                    QVariant value) // 设置index这一节点的属性数据为value
    {
        if (!index.isValid())
        {
            qDebug() << "error::invalid index value=" << value;
            return;
        }
        // 隐约记得，这里如果用的是智能指针，不能往下传到其他的函数，试一下
        auto* click_node = static_cast<ParaTreeNode*>(index.internalPointer());
        // QString para_name = click_node->data(0).toString();
        qDebug() << "*******click_node = " << click_node->data(0) << ", " << click_node->data(1);
        /**
         * 先switch state
         */
        int click_node_state = click_node->getState();
        qDebug() << "*******click_node_state = " << click_node_state;

        switch (click_node_state)
        {

        case OPTIONAL:
        {
            qDebug() << "---------print info of the option node-----------";
            printIndexInfo(index);
            click_node->printAllOptionChild();
            qDebug() << "click OPTIONAL 选中的选项为：" << value.toString();

            // ！！！！还没有更新para
            updatePara(index, value.toString().toStdString());
            makeChoice(index, value.toString()); // !!!!在该函数中进行选择和发送信号

            printIndexInfo(index);
            click_node->printAllOptionChild();
            break;
        }

        case EDITABLE:
        {
            qDebug()
                << "---------print info of the editable node --before change - begin-----------";
            printIndexInfo(index);
            qDebug() << "---------print info of the editable node --before change - end-----------";

            // 先更新para指针中的内容
            //  std::string name = click_node->data(0).toString().toStdString();
            //  para->setPara(name,value);          //---不能直接这样设置，
            updatePara(index, value.toString().toStdString());
            // 再处理树状视图的节点中对应的数据
            click_node->setData(value, 1);

            qDebug()
                << "---------print info of the editable node --after change - begin-----------";
            printIndexInfo(index);
            qDebug() << "---------print info of the editable node --after change - end-----------";

            break;
        }
        }
    }

    /**
     * 这里单独设置一系列函数去改para是因为，有些存的是指针，不能直接para->setPara
     * 需要先获得指针指向的对象，再对这个对象进行setpara
     */
    void ParaTreeModel::updatePara(QModelIndex index, const std::string& value)
    {
        auto* click_node = static_cast<ParaTreeNode*>(index.internalPointer());

        switch (this->model_type)
        {
        case SUN:
            updateSunPara(click_node, value);
            break;
        case LOCATION:
            updateLocationPara(click_node, value);
            break;
        case AIR:
            updateAirPara(click_node, value);
            break;
        case CAMERA:
            updateCameraPara(click_node, value);
            break;
        case TERRAIN:
            updateTerrainPara(click_node, value);
            break;
        case CLOUD:
            updateCloudPara(click_node, value);
            break;
        case NODE:
            updateNodePara(click_node, value);
            break;
        case HELIOSTAT:
            updateHeliostatPara(click_node, value);
            break;
        case RECEIVER:
            updateReceiverPara(click_node, value);
            break;
        case ORDINARY:
            updateOrdinaryPara(click_node, value);
            break;
        }
    }

    void ParaTreeModel::updateSunPara(ParaTreeNode*& click_node, const std::string& value)
    {
        std::string name = click_node->data(0).toString().toStdString();
        auto parent_node = click_node->parent();
        std::string parent_name = parent_node->data(0).toString().toStdString();

        auto sun_ptr = para.dynamicCast<Sun>();
        if (parent_name == "root")
        {
            // ::solar::setParaFromString(name, value.toString().toStdString(), sun_ptr.get());
            // setSunPara(toMemberName(name), value, sun_ptr.get());       //
            // 这里需要选择sunshape的类型，如果更改sunshape的话，用全局的setPara无法实现
            if (name == "sunshape")
            {
                // std::cout <<"  before std::any_cast\n";
                // SunShapeType current_sunshape_type =
                // std::any_cast<SunShapeType>(solar::getParaAsAny(toMemberName(name),sun_ptr.get()));
                auto sunshape = SOLAR_GET_VALUE(Sun, sunshape_, *sun_ptr);
                SunShapeType current_sunshape_type = sunshape->getType();
                // SunShapeType current_sunshape_type =
                // solar::getPara(toMemberName("sunshape_type"),sun_ptr.get()).value<SunShapeType>();
                // std::cout << "  after std::any_cast\n";
                SunShapeType value_sunshape_type = (SunShapeType)(SunShape::getSunshapeType(value));
                std::cout << "   current_sunshape = " << (int)current_sunshape_type
                          << ", value_sunshape = " << (int)value_sunshape_type << std::endl;
                if (current_sunshape_type != value_sunshape_type)
                {
                    // solar::setPara("sunshape_type_", value_sunshape_type, sun_ptr.get());
                    std::shared_ptr<SunShape> new_sunshape;
                    switch (value_sunshape_type)
                    {
                    case SunShapeType::kSunShapeBuie:
                    {
                        new_sunshape = std::make_shared<BuieSunShape>();
                        break;
                    }
                    case SunShapeType::kSunShapeGaussian:
                    {
                        new_sunshape = std::make_shared<GaussianSunShape>();
                        break;
                    }
                    case SunShapeType::kSunShapePillbox:
                    {
                        new_sunshape = std::make_shared<PillboxSunShape>();
                        break;
                    }
                    }
                    SOLAR_SET_VALUE(Sun, sunshape_, new_sunshape, *sun_ptr)
                }
                /**
                 * check
                 */
                // auto ret =
                // solar::getPara(toMemberName("sunshape_type"),sun_ptr.get()).value<SunShapeType>();
                auto altered_sunshape = SOLAR_GET_VALUE(Sun, sunshape_, *sun_ptr);
                auto sunshape_type = altered_sunshape->getType();
                std::cout
                    << "-------------check updateSunPara sunshape_type begin-----------------\n";
                std::cout << "name = " << name << ", origin = " << (int)current_sunshape_type
                          << ", value = " << (int)value_sunshape_type << std::endl;
                std::cout << "sunshape_ptr: type = " << (int)sunshape_type << std::endl;
                std::cout
                    << "-------------check updateSunPara sunshape_type end-----------------\n";
            }
        }
        else if (parent_name == "sunshape")
        {
            auto sunshape = SOLAR_GET_VALUE(Sun, sunshape_, *sun_ptr);
            sunshape->setPara(atof(value.c_str()));

            /**
             * check
             */
            std::cout << "----------check updateSunPara SunShape attribute begin-----------\n";
            auto ret = sunshape->getPara();
            auto sunshape_type = sunshape->getType();
            std::cout << "sunshape_type = " << (int)sunshape_type << ", name = " << name
                      << ", value = " << value << ", ret = " << ret << std::endl;
            std::cout << "----------check updateSunPara SunShape attribute end-----------\n";
        }
        else if (parent_name == "position")
        {
            // auto sunposition_ptr = std::any_cast<SunPosition*>(
            // solar::getParaPtr(toMemberName("sun_position"),sun_ptr.get()));
            auto sunposition_ptr = SOLAR_GET_VALUE(Sun, sun_position_, *sun_ptr);
            ;
            solar::setParaFromString(toMemberName(name), value, sunposition_ptr.get());

            /**
             * check
             */
            std::cout << "----------check updateSunPara SunPosition begin-----------\n";
            auto ret = solar::getParaAsString(toMemberName(name), sunposition_ptr.get());
            auto ret_qvariant = solar::getPara(toMemberName(name), sunposition_ptr.get());
            std::cout << "name = " << name << ", value = " << value << ", ret = " << ret
                      << std::endl;
            qDebug() << "ret_qvariant" << ret_qvariant;
            std::cout << "----------check updateSunPara SunPosition end-----------\n";
        }
        else
        { // 报错！！！
            exit(0);
        }
    }
    void ParaTreeModel::updateLocationPara(ParaTreeNode*& click_node, const std::string& value)
    {
        std::string name = click_node->data(0).toString().toStdString();
        // para->setPara(toMemberName(name),value);
        auto location_ptr = para.dynamicCast<Location>();
        solar::setParaFromString(toMemberName(name), value, location_ptr.get());

        /**
         * check
         */
        std::cout << "----------check updateLocationPara-begin-----------\n";
        auto ret = solar::getParaAsString(toMemberName(name), location_ptr.get());
        std::cout << "name = " << name << ", value = " << value << ", ret = " << ret << std::endl;
        std::cout << "----------check updateLocationPara-end-----------\n";
    }
    void ParaTreeModel::updateAirPara(ParaTreeNode*& click_node, const std::string& value)
    {
        std::cout << "6\n";
        std::string name = click_node->data(0).toString().toStdString();
        auto parent_node = click_node->parent();
        qDebug() << "7";
        std::string parent_name = parent_node->data(0).toString().toStdString();
        auto air_ptr = para.dynamicCast<Air>();
        qDebug() << "8";
        if (parent_name == "root")
        {
            // para->setPara(toMemberName(name),value);
            // setAirPara(toMemberName(name), value, air_ptr.get());
            /**
             * TODO::to be finished
             */
            if (name == "attenuation")
            {

                // AttenuationType current_attenuation_type = std::any_cast<AttenuationType>
                //                                             (solar::getParaAsAny(toMemberName(name),air_ptr.get()));
                auto attenuation = SOLAR_GET_VALUE(Air, attenuation_, *air_ptr);
                AttenuationType current_attenuation_type = attenuation->getType();
                // auto current_attenuation_type = solar::getPara(toMemberName("attenuation_type"),
                // air_ptr.get()).value<AttenuationType>();
                AttenuationType value_attenuation_type =
                    (AttenuationType)Attenuation::getAttenuationType(value);

                if (current_attenuation_type != value_attenuation_type)
                {
                    qDebug() << "current=" << (int)current_attenuation_type
                             << "value=" << (int)value_attenuation_type;
                    std::shared_ptr<Attenuation> new_attenuation;
                    // solar::setPara("attenuation_type_", value_attenuation_type, air_ptr.get());
                    switch (value_attenuation_type)
                    {
                    case AttenuationType::kAttenuationVacuum:
                    {
                        new_attenuation = std::make_shared<VacuumAttenuation>();
                        break;
                    }
                    case AttenuationType::kAttenuationExponential:
                    {
                        new_attenuation = std::make_shared<ExponentialAttenuation>();
                        break;
                    }
                    case AttenuationType::kAttenuationCustom:
                    {
                        new_attenuation = std::make_shared<CustomAttenuation>();
                        break;
                    }
                    }
                    SOLAR_SET_VALUE(Air, attenuation_, new_attenuation, *air_ptr)
                }
                qDebug() << "9";

                /**
                 * check
                 */
                // auto ret =
                // solar::getPara(toMemberName("attenuation_type"),air_ptr.get()).value<AttenuationType>();
                auto altered_attenuation = SOLAR_GET_VALUE(Air, attenuation_, *air_ptr);
                qDebug() << "11";
                // auto attenuation_type = altered_attenuation->getType();
                qDebug() << "12";
                std::cout
                    << "-------------check updateAirPara attenuation_type begin-----------------\n";
                std::cout << "name = " << name << ", origin = " << (int)current_attenuation_type
                          << ", value = " << (int)value_attenuation_type << std::endl;
                std::cout << "attenuation_ptr: type = " << (int)altered_attenuation->getType()
                          << std::endl;
                std::cout
                    << "-------------check updateAirPara attenuation_type end-----------------\n";
            }
        }
        else if (parent_name == "attenuation")
        {
            qDebug() << "10";
            // auto attenuation_ptr =
            // std::any_cast<Attenuation*>(solar::getParaPtr("attenuation_",air_ptr.get()));
            // attenuation_ptr->setPara(atof(value.c_str()));
            auto attenuation = solar::getPara(toMemberName("attenuation"), air_ptr.get())
                                   .value<std::shared_ptr<Attenuation>>();
            AttenuationType attenuation_type = attenuation->getType();
            // AttenuationType attenuation_type = solar::getPara(toMemberName("attenuation_type"),
            // air_ptr.get()).value<AttenuationType>();
            attenuation->setPara(atof(value.c_str()));

            /**
             * check
             */
            std::cout << "----------check updateAirPara Attenuation attribute begin-----------\n";
            auto ret = attenuation->getPara();
            std::cout << "attenuation_type = " << (int)attenuation_type << ", name = " << name
                      << ", value = " << value << ", ret = " << ret << std::endl;
            std::cout << "----------check updateAirPara Attenuation attribute end-----------\n";
        }
    }
    void ParaTreeModel::updateCameraPara(ParaTreeNode*& click_node, const std::string& value)
    {
        std::string name = click_node->data(0).toString().toStdString();
        // para->setPara(toMemberName(name),value);
        auto camera_ptr = para.dynamicCast<Camera>();
        solar::setParaFromString(toMemberName(name), value, camera_ptr.get());
    }
    void ParaTreeModel::updateTerrainPara(ParaTreeNode*& click_node, const std::string& value)
    {
        std::string name = click_node->data(0).toString().toStdString();
        // para->setPara(toMemberName(name),value);
        auto terrain_ptr = para.dynamicCast<Terrain>();
        solar::setParaFromString(toMemberName(name), value, terrain_ptr.get());
    }
    /**
     * !!!!!!!!!!!!!cloud 的文件路径
     */
    void ParaTreeModel::updateCloudPara(ParaTreeNode*& click_node, const std::string& value)
    {

        std::string name = click_node->data(0).toString().toStdString();
        auto cloud_ptr = para.dynamicCast<Cloud>();

        // auto grid_ptr = std::any_cast<Grid*>(solar::getParaPtr("grid_", cloud_ptr.get()));
        // auto grid_ptr = solar::getPara(toMemberName("grid"),
        // cloud_ptr.get()).value<std::shared_ptr<Grid>>();
        solar::setParaFromString(toMemberName(name), value, cloud_ptr.get());
        // auto grid_ptr = cloud->getPara(toMemberName("grid")).value<std::shared_ptr<Grid>>();
        // grid_ptr->setPara(toMemberName(name),value);

        // cloud->testPrint();
    }
    void ParaTreeModel::updateNodePara(ParaTreeNode*& click_node, const std::string& value)
    {
        std::string name = click_node->data(0).toString().toStdString();
        // para->setPara(toMemberName(name),value);
        auto node_ptr = para.dynamicCast<Node>();
        solar::setParaFromString(toMemberName(name), value, node_ptr.get());

        // para.dynamicCast<Node>()->testPrint();
    }

    /**
     * TODO: add more update details about material
     * It's not the same as the HeliostatPara in "analytical_model"
     */
    void ParaTreeModel::updateHeliostatPara(ParaTreeNode*& click_node, const std::string& value)
    {
        auto parent_node = click_node->parent();
        std::string parent_name = parent_node->data(0).toString().toStdString();
        std::string name = click_node->data(0).toString().toStdString();
        auto heliostat_ptr = para.dynamicCast<Heliostat>();

        if (parent_name == "root")
        {
            if (name == "geometry")
            {
                auto geometry_ptr = SOLAR_GET_VALUE(Heliostat, geometry_, *heliostat_ptr);
                // GeometryType current_geometry_type =
                // std::any_cast<GeometryType>(solar::getParaAsAny(toMemberName("geometry_type"),
                // heliostat_ptr.get()));
                GeometryType current_geometry_type = geometry_ptr->getType();
                auto value_geometry_type = solar::getEnumValue<GeometryType>(value);

                if (current_geometry_type != value_geometry_type)
                {
                    // solar::setPara("geometry_type_", value_geometry_type, heliostat_ptr.get());
                    std::shared_ptr<Geometry> new_geometry;
                    switch (value_geometry_type)
                    {
                    case GeometryType::kGeometryRectangle:
                    {
                        new_geometry = std::make_shared<Rectangle>();
                        break;
                    }
                    case GeometryType::kGeometryParabolic:
                    {
                        new_geometry = std::make_shared<Parabolic>();
                        break;
                    }
                    case GeometryType::kGeometryBSpline:
                    {
                        new_geometry = std::make_shared<BSpline>();
                        break;
                    }
                    case GeometryType::kGeometryMesh:
                    {
                        new_geometry = std::make_shared<Mesh>();
                        break;
                    }
                    }
                    SOLAR_SET_VALUE(Heliostat, geometry_, new_geometry, *heliostat_ptr)
                }
            }
            else if (name == "material")
            {
                // MaterialType current_material_type =
                // std::any_cast<MaterialType>(solar::getParaAsAny(toMemberName("material_type"),
                // heliostat_ptr.get()));
                auto material_ptr = SOLAR_GET_VALUE(Heliostat, material_, *heliostat_ptr);
                MaterialType current_material_type = material_ptr->getType();
                // MaterialType current_material_type =
                // solar::getPara(toMemberName("material_type"),
                // heliostat_ptr.get()).value<MaterialType>();
                auto value_material_type = solar::getEnumValue<MaterialType>(value);

                // qDebug() <<"current material="<<(int)current_material_type<<" value
                // material="<<(int)value_material_type;

                if (current_material_type != value_material_type)
                {
                    // solar::setPara("material_type_",value_material_type, heliostat_ptr.get());
                    std::shared_ptr<Material> new_material;
                    switch (value_material_type)
                    {
                    case MaterialType::kMaterialReflect:
                    {
                        new_material = std::make_shared<Reflect>();
                        break;
                    }
                    case MaterialType::kMaterialRefract:
                    {
                        new_material = std::make_shared<Refract>();
                        break;
                    }
                    }
                    solar::setPara("material_", new_material, heliostat_ptr.get());
                }
            }
            else
            {
                solar::setParaFromString(toMemberName(name), value, heliostat_ptr.get());
            }
        }
        else if (parent_name == "geometry")
        {
            // auto geometry_ptr =
            // std::any_cast<Geometry*>(solar::getParaPtr("geometry_",heliostat_ptr.get()));
            // solar::setParaFromString(toMemberName(name), value, geometry_ptr);  //
            // ！！！！！！！！！！这里无法实现!!!!!
            // geometry_ptr->setPara(toMemberName(name),value);
            auto geometry = SOLAR_GET_VALUE(Heliostat, geometry_, *heliostat_ptr);
            GeometryType geometry_type = geometry->getType();
            // GeometryType geometry_type =
            // std::any_cast<GeometryType>(solar::getParaAsAny("geometry_type_",
            // heliostat_ptr.get())); GeometryType geometry_type =
            // solar::getPara(toMemberName("geometry_type"),
            // heliostat_ptr.get()).value<GeometryType>();

            switch (geometry_type)
            {
            case GeometryType::kGeometryRectangle:
            {
                auto rectangle_geometry_ptr = std::dynamic_pointer_cast<Rectangle>(geometry);
                solar::setParaFromString(toMemberName(name), value, rectangle_geometry_ptr.get());
                break;
            }
            case GeometryType::kGeometryParabolic:
            {
                auto parabolic_geometry_ptr = std::dynamic_pointer_cast<Parabolic>(geometry);
                solar::setParaFromString(toMemberName(name), value, parabolic_geometry_ptr.get());
                break;
            }
            case GeometryType::kGeometryBSpline:
            {
                auto bspline_geometry_ptr = std::dynamic_pointer_cast<BSpline>(geometry);
                solar::setParaFromString(toMemberName(name), value, bspline_geometry_ptr.get());
                break;
            }
            case GeometryType::kGeometryMesh:
            {
                auto mesh_geometry_ptr = std::dynamic_pointer_cast<Mesh>(geometry);
                solar::setParaFromString(toMemberName(name), value, mesh_geometry_ptr.get());
                break;
            }
            }
        }
        else if (parent_name == "material")
        {
            // auto parent_ptr =
            // para->getPara(toMemberName(parent_name)).value<std::shared_ptr<Material>>();
            // parent_ptr->setPara(toMemberName(name),value);
            auto material = SOLAR_GET_VALUE(Heliostat, material_, *heliostat_ptr);
            MaterialType material_type = material->getType();
            // MaterialType material_type =
            // std::any_cast<MaterialType>(solar::getParaAsAny("material_type_",
            // heliostat_ptr.get())); MaterialType material_type =
            // solar::getPara(toMemberName("material_type"),
            // heliostat_ptr.get()).value<MaterialType>();

            switch (material_type)
            {
            case MaterialType::kMaterialReflect:
            {
                auto reflect_material_ptr = std::dynamic_pointer_cast<Reflect>(material);
                if (name == "slope_error_type")
                {
                    auto current_slopeerror_type =
                        solar::getPara(toMemberName(name), reflect_material_ptr.get())
                            .value<SlopeErrorType>();
                    auto value_slopeerror_type = solar::getEnumValue<SlopeErrorType>(value);
                    if (current_slopeerror_type != value_slopeerror_type)
                    {
                        solar::setPara(toMemberName(name), value_slopeerror_type,
                                       reflect_material_ptr.get());
                    }
                }
                else
                {
                    solar::setParaFromString(toMemberName(name), value, reflect_material_ptr.get());
                }

                break;
            }
            case MaterialType::kMaterialRefract:
            {
                auto refract_material_ptr = std::dynamic_pointer_cast<Refract>(material);
                if (name == "slope_error_type")
                {
                    auto current_slopeerror_type =
                        SOLAR_GET_VALUE(Refract, slope_error_type_, *refract_material_ptr);
                    auto value_slopeerror_type = solar::getEnumValue<SlopeErrorType>(value);
                    if (current_slopeerror_type != value_slopeerror_type)
                    {
                        SOLAR_SET_VALUE(Refract, slope_error_type_, value_slopeerror_type,
                                        *refract_material_ptr)
                    }
                }
                else
                {
                    solar::setParaFromString(toMemberName(name), value, refract_material_ptr.get());
                }
                break;
            }
            }
        }
        else
        {
            qDebug() << "error::updateHeliostatPara::do not has this type of parent_name: "
                     << QString::fromStdString(parent_name);
        }
    }
    void ParaTreeModel::updateReceiverPara(ParaTreeNode*& click_node, const std::string& value)
    {
        auto parent_node = click_node->parent();
        std::string parent_name = parent_node->data(0).toString().toStdString();
        std::string name = click_node->data(0).toString().toStdString();
        auto receiver_ptr = para.dynamicCast<Receiver>();
        if (parent_name == "root")
        {
            if (name == "geometry")
            {
                auto geometry_ptr = SOLAR_GET_VALUE(Receiver, geometry_, *receiver_ptr);
                GeometryType current_geometry_type = geometry_ptr->getType();
                // GeometryType current_geometry_type =
                // std::any_cast<GeometryType>(solar::getParaAsAny(toMemberName("geometry_type"),
                // receiver_ptr.get())); GeometryType current_geometry_type =
                // solar::getPara(toMemberName("geometry_type"),
                // receiver_ptr.get()).value<GeometryType>();
                auto value_geometry_type = solar::getEnumValue<GeometryType>(value);

                std::cout << "current=" << (int)current_geometry_type
                          << " value=" << (int)value_geometry_type << std::endl;

                if (current_geometry_type != value_geometry_type)
                {
                    // solar::setPara("geometry_type_", value_geometry_type, receiver_ptr.get());
                    std::shared_ptr<Geometry> new_geometry;
                    switch (value_geometry_type)
                    {
                    case GeometryType::kGeometryRectangle:
                    {
                        new_geometry = std::make_shared<Rectangle>();
                        break;
                    }
                    case GeometryType::kGeometryCylinder:
                    {
                        new_geometry = std::make_shared<Cylinder>();
                        break;
                    }
                    case GeometryType::kGeometryRefinedRectangle:
                    {
                        new_geometry = std::make_shared<RefinedRectangle>();
                        break;
                    }
                    case GeometryType::kGeometryRefinedCylinder:
                    {
                        new_geometry = std::make_shared<RefinedCylinder>();
                        break;
                    }
                    }
                    SOLAR_SET_VALUE(Receiver, geometry_, new_geometry, *receiver_ptr)
                }
            }
            else if (name == "material")
            {
                auto material_ptr = solar::getPara("material_", receiver_ptr.get())
                                        .value<std::shared_ptr<Material>>();
                MaterialType current_material_type = material_ptr->getType();
                // MaterialType current_material_type =
                // std::any_cast<MaterialType>(solar::getParaAsAny(toMemberName("material_type"),
                // receiver_ptr.get())); MaterialType current_material_type =
                // solar::getPara(toMemberName("material_type"),
                // receiver_ptr.get()).value<MaterialType>();
                auto value_material_type = solar::getEnumValue<MaterialType>(value);
                if (current_material_type != value_material_type)
                {
                    //!!!!!!!!!!不会执行
                    // solar::setPara("material_type_",value_material_type, receiver_ptr.get());
                }
            }
            else
            {
                solar::setParaFromString(toMemberName(name), value, receiver_ptr.get());
            }
        }
        else if (parent_name == "geometry")
        {
            auto geometry = SOLAR_GET_VALUE(Receiver, geometry_, *receiver_ptr);
            // GeometryType geometry_type =
            // std::any_cast<GeometryType>(solar::getParaAsAny("geometry_type_",
            // receiver_ptr.get())); GeometryType geometry_type =
            // solar::getPara(toMemberName("geometry_type"),
            // receiver_ptr.get()).value<GeometryType>();
            GeometryType geometry_type = geometry->getType();

            switch (geometry_type)
            {
            case GeometryType::kGeometryRectangle:
            {
                auto rectangle_geometry_ptr = std::dynamic_pointer_cast<Rectangle>(geometry);
                solar::setParaFromString(toMemberName(name), value, rectangle_geometry_ptr.get());
                break;
            }
            case GeometryType::kGeometryCylinder:
            {
                auto cylinder_geometry_ptr = std::dynamic_pointer_cast<Cylinder>(geometry);
                solar::setParaFromString(toMemberName(name), value, cylinder_geometry_ptr.get());
                break;
            }
            case GeometryType::kGeometryRefinedRectangle:
            {
                auto refinedrectangle_geometry_ptr =
                    std::dynamic_pointer_cast<RefinedRectangle>(geometry);
                solar::setParaFromString(toMemberName(name), value,
                                         refinedrectangle_geometry_ptr.get());
                break;
            }
            case GeometryType::kGeometryRefinedCylinder:
            {
                auto refinedcylinder_geometry_ptr =
                    std::dynamic_pointer_cast<RefinedCylinder>(geometry);
                solar::setParaFromString(toMemberName(name), value,
                                         refinedcylinder_geometry_ptr.get());
                break;
            }
            }
        }
        else if (parent_name == "material")
        {
            // auto parent_ptr =
            // para->getPara(toMemberName(parent_name)).value<std::shared_ptr<Material>>();
            // parent_ptr->setPara(toMemberName(name),value);
            auto material = SOLAR_GET_VALUE(Receiver, material_, *receiver_ptr);
            // MaterialType material_type =
            // std::any_cast<MaterialType>(solar::getParaAsAny("material_type_",
            // receiver_ptr.get())); MaterialType material_type =
            // solar::getPara(toMemberName("material_type"),
            // receiver_ptr.get()).value<MaterialType>();
            MaterialType material_type = material->getType();
            switch (material_type)
            {
            case MaterialType::kMaterialAbsorb:
            {
                auto absorb_material_ptr = std::dynamic_pointer_cast<Absorb>(material);
                solar::setParaFromString(toMemberName(name), value, absorb_material_ptr.get());
                break;
            }
            }
        }
        else
        {
            qDebug() << "error::updateReceiverPara::do not has this type of parent_name: "
                     << QString::fromStdString(parent_name);
        }
    }

    /**
     * TODO:: to be finished
     *          add more geometries and materials
     */
    void ParaTreeModel::updateOrdinaryPara(ParaTreeNode*& click_node, const std::string& value)
    {
        auto parent_node = click_node->parent();
        std::string parent_name = parent_node->data(0).toString().toStdString();
        std::string name = click_node->data(0).toString().toStdString();
        auto ordinary_ptr = para.dynamicCast<Ordinary>();

        if (parent_name == "root")
        {
            if (name == "geometry")
            {
                auto geometry_ptr = SOLAR_GET_VALUE(Ordinary, geometry_, *ordinary_ptr);
                GeometryType current_geometry_type = geometry_ptr->getType();
                // GeometryType current_geometry_type =
                // solar::getPara(toMemberName("geometry_type"),
                // ordinary_ptr.get()).value<GeometryType>();
                auto value_geometry_type = solar::getEnumValue<GeometryType>(value);
                if (current_geometry_type != value_geometry_type)
                {
                    // solar::setPara("geometry_type_", value_geometry_type, ordinary_ptr.get());
                    /**
                     * TODO::设置ordinary的geometry
                     */
                }
            }
        }
        else if (parent_name == "geometry")
        {
            auto geometry = SOLAR_GET_VALUE(Ordinary, geometry_, *ordinary_ptr);
            GeometryType geometry_type = geometry->getType();
            // GeometryType geometry_type =
            // std::any_cast<GeometryType>(solar::getParaAsAny("geometry_type_",
            // receiver_ptr.get())); GeometryType geometry_type =
            // solar::getPara(toMemberName("geometry_type"),
            // ordinary_ptr.get()).value<GeometryType>();
            switch (geometry_type)
            {
            case GeometryType::kGeometryCylinder:
            {
                auto cylinder_geometry_ptr = std::dynamic_pointer_cast<Cylinder>(geometry);
                solar::setParaFromString(toMemberName(name), value, cylinder_geometry_ptr.get());
                break;
            }
            case GeometryType::kGeometryRectangle:
            {
                auto rectangle_geometry_ptr = std::dynamic_pointer_cast<Rectangle>(geometry);
                solar::setParaFromString(toMemberName(name), value, rectangle_geometry_ptr.get());
                break;
            }
            }
        }
    }

    /**
     * ------------------------------------------------------------
     */
    auto
    ParaTreeModel::getNodePara(const QModelIndex& index) -> QString // 获取index这一节点的para数据
    {
        if (!index.isValid())
        {
            return "";
        }
        auto* current_node = static_cast<ParaTreeNode*>(index.internalPointer());
        QVariant para_data = current_node->data(1);
        return para_data.toString();
    }

    auto ParaTreeModel::isNodeEditable(const QModelIndex& index) -> bool
    {
        if (!index.isValid())
        {
            return false;
        }
        auto* current_node = static_cast<ParaTreeNode*>(index.internalPointer());
        ParaState para_state = current_node->getState();
        return para_state == EDITABLE;
    }
    auto ParaTreeModel::isNodeOptional(const QModelIndex& index) -> bool
    {
        if (!index.isValid())
        {
            return false;
        }
        auto* current_node = static_cast<ParaTreeNode*>(index.internalPointer());
        ParaState para_state = current_node->getState();
        return para_state == OPTIONAL;
    }

    auto ParaTreeModel::getNodeOptionList(const QModelIndex& index) -> QList<QString>
    {
        if (!index.isValid())
        {
            return {};
        }
        auto* current_node = static_cast<ParaTreeNode*>(index.internalPointer());
        return current_node->getOptions();
    }

    /**
     * 处理界面上的显示
     *
     * 本来进行移除和插入一些行，应该使用beginRemoveRows()、endRemoveRows()、beginInsertRows()、endInsertRows()
     * 但是实践中发现会出现各种问题：ui界面不能及时响应（需要toggle之后或者焦点改变后界面才会更新）、无法remove界面中的行
     * 为了避免这些问题，这里使用beginResetModel()、endResetModel()来进行处理
     */
    void ParaTreeModel::makeChoice(const QModelIndex& index, const QString& option) // 做出选择
    {
        if (!index.isValid())
        {
            return;
        }
        auto* click_node = static_cast<ParaTreeNode*>(index.internalPointer());

        makeChoice(click_node, option);
        // // 首先，改变该节点的选项
        // click_node->setData(option, 1);
        // emit dataChanged(index, index);

        // int parent_row = index.row();
        // if (click_node->childCount() != 0)
        // {
        //     beginResetModel();
        //     click_node->deleteAllChild();
        //     endResetModel();
        // }

        // // 把选项的孩子列表添加到节点的孩子列表中
        // auto current_option_childnodes = click_node->getOptionChilds(option);
        // int count = current_option_childnodes.size();

        // beginResetModel();
        // for(int i=0;i<count;i++)
        // {
        //     click_node->appendChild(current_option_childnodes[i]);
        // }
        // endResetModel();
    }
    void ParaTreeModel::makeChoice(ParaTreeNode*& click_node, const QString& option)
    {
        // 首先，改变该节点的选项
        click_node->setData(option, 1);

        /**
         * todo:: validate the signial is not required
         */
        // emit dataChanged(index, index);

        // int parent_row = index.row();
        if (click_node->childCount() != 0)
        {
            beginResetModel();
            click_node->deleteAllChild();
            endResetModel();
        }

        // 把选项的孩子列表添加到节点的孩子列表中
        auto current_option_childnodes = click_node->getOptionChilds(option);
        auto count = current_option_childnodes.size();

        beginResetModel();
        for (int i = 0; i < count; i++)
        {
            click_node->appendChild(current_option_childnodes[i]);
        }
        endResetModel();
    }

    // removeRows以及insertRows这两个函数可以删去
    auto ParaTreeModel::removeRows(int row, int count, const QModelIndex& parent) -> bool
    {
        auto* click_node = static_cast<ParaTreeNode*>(parent.internalPointer());
        /*
            问题：即使用begin...end...删去某些行，UI界面中，这些行虽然逻辑上已经删去，不属于任何父亲，对应的index也不合法
                    但是仍然存在于UI界面上...
            不清楚原因...
        */
        beginRemoveRows(parent, row, row + count - 1);
        click_node->deleteAllChild();
        endRemoveRows();
        return true;
    }
    auto ParaTreeModel::insertRows(int row, int count, const QModelIndex& parent) -> bool
    {
        auto* click_node = static_cast<ParaTreeNode*>(parent.internalPointer());
        QString option = click_node->data(1).toString();
        auto current_option_childnodes = click_node->getOptionChilds(option);

        // beginInsertRows(parent,row,row+count-1);
        beginInsertRows(parent, 0, 0);
        for (int i = 0; i < count; i++)
        {
            click_node->appendChild(current_option_childnodes[i]);
        }
        endInsertRows();
        return true;
    }

    auto ParaTreeModel::getCurrentOptionId(const QModelIndex& index) -> int
    {
        if (!index.isValid())
        {
            return -1;
        }
        auto* click_node = static_cast<ParaTreeNode*>(index.internalPointer());
        return click_node->getCurrentOptionId();
    }

    void ParaTreeModel::setLabelTxt(QString label_txt) { this->label_txt = label_txt; }
    auto ParaTreeModel::getLabelTxt() -> QString
    {
        // qDebug() << "HINT::ParaTreeModel::getLabelTxt::label_txt = "<<label_txt;
        return label_txt;
    }

    auto ParaTreeModel::getParaPtr() -> Para* { return para.get(); }

    void ParaTreeModel::printIndexInfo(QModelIndex index)
    {
        if (!index.isValid())
        {
            qDebug() << "ERROR::invalid index";
            return;
        }
        auto* click_node = static_cast<ParaTreeNode*>(index.internalPointer());
        qDebug() << "--index: row = " << index.row();
        qDebug() << "--index = " << index;
        if (click_node == nullptr) // ！！！这里：注意index不存在的情况
        {
            qDebug() << "ERROR::INVALID INDEX";
        }
        else
        {
            click_node->printInfo();
        }
    }

} // namespace solar
